home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
a_utils
/
expanded.lha
/
test_suite
/
thex.C
< prev
Wrap
C/C++ Source or Header
|
1992-03-19
|
16KB
|
515 lines
//
// Linear-Affine-Projective Geometry Package
//
// thex.C
//
// $Header$
//
// William J.R. Longabaugh
// University of Washington
//
// Thesis examples for the linear-affine-projective geometry
// package described in William J.R. Longabaugh, "An Expanded
// System for Coordinate-Free Geometric Programming", Master's
// thesis, University of Washington, 1992.
//
// Copyright (c) 1992, William J.R. Longabaugh
// Copying, use and development for non-commercial purposes permitted.
// All rights for commercial use reserved.
// This software is unsupported and without warranty; it is
// provided "as is".
//
// ***********************************************************************
#include "Lap.h"
#include <math.h>
extern void thex1(void);
extern void thex2(void);
extern void thex3(void);
extern void thex4(void);
extern void thex5(void);
extern void thex6(void);
extern void thex7(void);
// ***********************************************************************
int main(void)
{
thex1();
thex2();
thex3();
thex4();
thex5();
thex6();
thex7();
return (0);
}
// ***********************************************************************
void thex1(void)
{
// Create the range and domain space for the map. Note that
// since this is a second-degree surface, the domain space
// of the MAM is a cartesian product space with two components:
ASpace param("Parameter space", 2, TRUE);
Simplex smp1 = param.StdSimplex();
ASpace domsp("Cart. prod. domain space",
SpaceList(param, 2), FALSE);
ASpace rng("Range space", 3, TRUE);
Frame fr2 = rng.StdBasis();
// Construct the symmetry set specification. Since this is
// a fully symmetric map, the list has one entry (2):
IntList symspec(1);
symspec[0] = 2;
// Construct the control net for the surface. Note the ordering
// of the points in the net. List concatenation is used to
// build a large net easily:
APoint aa(fr2, ScalarList(0.0, 0.0, 0.0, 1.0));
APoint ab(fr2, ScalarList(1.0, 0.0, 0.7, 1.0));
APoint bb(fr2, ScalarList(2.0, 0.0, 0.0, 1.0));
APoint ac(fr2, ScalarList(0.5, 1.0, 0.7, 1.0));
APoint bc(fr2, ScalarList(1.5, 1.0, 0.7, 1.0));
APoint cc(fr2, ScalarList(1.0, 2.0, 0.0, 1.0));
GeObList net = GeObList(aa, ab, bb) + GeObList(ac, bc, cc);
// Build the multi-affine map for the surface:
MAM surfmap = MAM(domsp, symspec, BasisList(smp1), rng, net);
// Build a point in the parameter space for evaluating the map:
APoint pt1(smp1, ScalarList(0.4, 0.3, 0.3));
// Evaluate the map to obtain a point on the surface. Note
// that the argument to the map is a tuple with the same
// point repeated, so the result is on the surface:
APoint argpt1(domsp, pt1, pt1);
APoint surfpt = surfmap(argpt1);
// Partially evaluate the map once on the point pt1 in the
// parameter space. The result is an affine map:
GeObList partial(2);
partial[0] = pt1;
AffineMap tanmap = surfmap(param, partial);
// Mapping vectors in the parameter space through this map will
// produce vectors tangent to the surface at the point surfpt.
// Use vectors from the standard frame:
AVector surftan1 = tanmap(param.StdBasis()[0]);
AVector surftan2 = tanmap(param.StdBasis()[1]);
// Take the cross product of the resulting vectors to obtain a
// normal vector. Normalize the length and cast it into a dual
// vector. Note that the argument to sqrt() must be cast to
// a scalar manually; if the sqrt() function were not being used,
// no casting would be needed:
MLM rngcross = rng.GetSpace(TANGENT).CrossProduct();
MLM rnginner = rng.GetSpace(TANGENT).InnerProduct();
AVector nvec = rngcross(GeObList(surftan1, surftan2));
nvec = nvec / sqrt(rnginner(GeObList(nvec, nvec)).ToScalar());
Vector surfnorm = nvec.Dual();
cout << nvec;
cout << surfnorm;
// Use this to calculate the cosine of the angle of a unit
// vector from the normal:
AVector testvec(fr2, ScalarList(1.0, 0.0, 0.0, 0.0));
Scalar angle = surfnorm.Apply(testvec);
// Extract the coordinates of the surface point with respect to
// the standard basis:
ScalarList surfptCoords = fr2(surfpt);
cout << "Cosine of angle: " << angle << "\n";
cout << surfptCoords;
}
// ***********************************************************************
void thex2(void)
{
// Create the parameter spaces, range space, and domain space
// for the map:
ASpace paramX("Parameter space X", 1, TRUE);
Simplex smp1 = paramX.StdSimplex();
ASpace paramY("Parameter space Y", 1, TRUE);
Simplex smp2 = paramY.StdSimplex();
ASpace rng("Range space", 3, TRUE);
Frame fr1 = rng.StdBasis();
// The domain space of the MAM is a cartesian product space with
// four components, two in each symmetry set:
ASpace domsp("Cart. prod. domain space",
SpaceList(paramX, 2) + SpaceList(paramY, 2),
FALSE);
// Construct the symmetry set specification. There are two
// sets, each with two spaces (2,2):
IntList symspec(2);
symspec[0] = 2;
symspec[1] = 2;
// Construct the control net for the surface. Note the ordering
// of the points in the net. Use list concatenation to build
// a large list easily:
APoint aa_cc(fr1, ScalarList(0.0, 0.0, 0.0, 1.0));
APoint ab_cc(fr1, ScalarList(1.0, 0.0, 0.5, 1.0));
APoint bb_cc(fr1, ScalarList(2.0, 0.0, 0.0, 1.0));
APoint aa_cd(fr1, ScalarList(0.0, 1.0, 0.5, 1.0));
APoint ab_cd(fr1, ScalarList(1.0, 1.0, 1.0, 1.0));
APoint bb_cd(fr1, ScalarList(2.0, 1.0, 0.5, 1.0));
APoint aa_dd(fr1, ScalarList(0.0, 2.0, 0.0, 1.0));
APoint ab_dd(fr1, ScalarList(1.0, 2.0, 0.5, 1.0));
APoint bb_dd(fr1, ScalarList(2.0, 2.0, 0.0, 1.0));
GeObList net = GeObList(aa_cc, aa_cd, aa_dd) +
GeObList(ab_cc, ab_cd, ab_dd) +
GeObList(bb_cc, bb_cd, bb_dd);
// Build the multi-affine map for the surface:
MAM surfmap(domsp, symspec, BasisList(smp1, smp2), rng, net);
// Evaluate the map to obtain a point on the surface.
// First build a point in each parameter space, then
// build a point tuple:
APoint x(smp1, ScalarList(0.55, 0.45));
APoint y(smp2, ScalarList(0.3, 0.7));
APoint argpt1(domsp, GeObList(x, x) + GeObList(y, y));
APoint surfpt = surfmap(argpt1);
// Extract the coordinates of the surface point with respect to
// the standard basis:
ScalarList surfptCoords = fr1(surfpt);
cout << surfptCoords;
}
// ***********************************************************************
void thex3(void)
{
// Represent a rational quadratic Bezier surface. First create
// the range and domain space for the map. Both are
// affine spaces:
ASpace param("Parameter space", 2, TRUE);
Simplex smp1 = param.StdSimplex();
ASpace domsp("Cart. prod. domain space",
SpaceList(param, 2), FALSE);
ASpace rng("Range space", 3, TRUE);
Frame fr2 = rng.StdBasis();
// Construct the symmetry set specification. Since this is a
// fully symmetric map, the list has one entry (2):
IntList symspec(1);
symspec[0] = 2;
// Construct the control net for the surface. Since this is a
// rational map, each control point has an associated
// scalar weight, so build the corresponding list of scalars:
APoint aa(fr2, ScalarList(0.0, 0.0, 0.0, 1.0));
APoint ab(fr2, ScalarList(1.0, 0.0, 0.7, 1.0));
APoint bb(fr2, ScalarList(2.0, 0.0, 0.0, 1.0));
APoint ac(fr2, ScalarList(0.5, 1.0, 0.7, 1.0));
APoint bc(fr2, ScalarList(1.5, 1.0, 0.7, 1.0));
APoint cc(fr2, ScalarList(1.0, 2.0, 0.0, 1.0));
GeObList net = GeObList(aa, ab, bb) + GeObList(ac, bc, cc);
ScalarList weights = ScalarList(2.4, 1.3, -3.5) +
ScalarList(5.1, 0.7, 4.6);
// Build the multi-affine map used to represent the surface.
// The range of this map will be the linearization space of
// the affine space containing the surface. The control net
// of affine points is converted into a control net of vectors
// in the linearization space:
VSpace tempRange = rng.GetSpace(LINEARIZATION);
GeObList vecnet(6);
for (int i = 0; i < 6; i++) {
vecnet[i] = weights[i] * net[i];
}
MAM surfmap(domsp, symspec,
BasisList(smp1), tempRange, vecnet);
// Build a point in the parameter space for evaluating the map:
APoint pt1(smp1, ScalarList(0.2, 0.3, 0.5));
// Evaluate the map to obtain a point on the surface. The
// MAM returns a vector in the linearization space. This
// is converted into a projective point in the projective
// completion space (unless it is the zero vector). The
// projective point is then converted to an affine point
// in the original range space unless it is a point at
// infinity:
APoint argpt1(domsp, pt1, pt1);
APoint surfpt = surfmap(argpt1).MapTo(VEC_EC)
.MapTo(PROJ_POINT)
.MapTo(AFF_POINT);
// Extract the coordinates of the surface point with respect to
// the standard basis:
ScalarList surfptCoords = fr2(surfpt);
cout << surfptCoords;
}
// ***********************************************************************
void thex4(void)
{
// Build the affine space and get a simplex and frame:
ASpace workspace("Working space", 3, TRUE);
Simplex smp1 = workspace.StdSimplex();
Frame fra1 = workspace.StdBasis();
// Define the face with three points, and three vectors
// representing normals at each vertex. Convert each normal
// vector into its corresponding dual vector (linear
// functional):
APoint pt1(fra1, ScalarList(7.2, 1.4, 5.5, 1.0));
APoint pt2(fra1, ScalarList(3.2, 5.4, 9.8, 1.0));
APoint pt3(fra1, ScalarList(1.2, 4.1, 6.7, 1.0));
AVector nv1(fra1, ScalarList(2.5, 3.6, 1.8, 0.0));
AVector nv2(fra1, ScalarList(6.6, 3.4, 1.6, 0.0));
AVector nv3(fra1, ScalarList(7.2, 5.1, 3.9, 0.0));
Vector norm1 = nv1.Dual();
Vector norm2 = nv2.Dual();
Vector norm3 = nv3.Dual();
// We wish to calculate the linear interpolation of the normal
// for any given point on the face. This is an affine map from
// 2D affine subset defined by the face to the affine subset
// defined by the three vectors in the dual space. Define the
// domain and range subsets. Remember that these last the life
// of the program (their storage space is not released):
ASubSet face("face", workspace, GeObList(pt1, pt2, pt3));
ASubSet norms("norms", workspace.GetSpace(TANG_DUAL),
GeObList(norm1, norm2, norm3));
// Define the map that does interpolation of the normals:
AffineMap interp(face, GeObList(pt1, pt2, pt3),
norms, GeObList(norm1, norm2, norm3));
// Create a point on the face and calculate the corresponding
// normal:
APoint testpt = .6 * pt1 + .2 * pt2 + .2 * pt3;
Vector intnorm = interp(testpt);
cout << intnorm;
// Note that the interpolation map is invertible. Given a
// normal from the affine subset, get the corresponding
// point on the face:
AffineMap invint = interp.Inv();
Vector testnorm = .5 * norm1 + .1 * norm2 + .4 * norm3;
APoint intpt = invint(testnorm);
cout << intpt;
}
// ***********************************************************************
void thex5(void)
{
// Create an affine space. The domain of the determinant is the
// tangent space, while the range is the real numbers:
ASpace workspace("Working space", 3, TRUE);
Simplex smp1 = workspace.StdSimplex();
Frame fra1 = workspace.StdBasis();
VSpace wsTangent = workspace.GetSpace(TANGENT);
VBasis bas1 = wsTangent.StdBasis();
// Construct the symmetry set specification. Determinants in
// 3D spaces take 3 arguments, and the negative sign indicates
// the map is antisymmetric:
IntList symspec(1);
symspec[0] = -3;
// Define the MLM. The ``control net'' for the map is a single
// vector: the scalar 1.0 in the reals.
VSpace domsp("Cart. prod. domain space",
SpaceList(wsTangent, 3), FALSE);
MLM det(domsp, symspec, BasisList(bas1),
Reals, GeObList(Vector(1.0)));
// Build a volume out of vectors:
GeObList volume(3);
APoint pt1(fra1, ScalarList(7.2, 1.4, 5.5, 1.0));
APoint pt2(fra1, ScalarList(3.2, 5.4, 9.8, 1.0));
APoint pt3(fra1, ScalarList(1.2, 4.1, 6.7, 1.0));
APoint pt4(fra1, ScalarList(3.4, 9.5, 7.1, 1.0));
volume[0] = pt2 - pt1;
volume[1] = pt3 - pt1;
volume[2] = pt4 - pt1;
// Find the signed volume represented by the vectors. The result
// of the map is a vector in the special space "Reals", which
// is manually cast to a scalar:
Scalar res = det(volume).ToScalar();
cout << "Determinant: " << res << "\n";
}
// ***********************************************************************
void thex6(void)
{
// Create a 3D affine space:
ASpace workspace("Working space", 3, TRUE);
Simplex smp1 = workspace.StdSimplex();
Frame fra1 = workspace.StdBasis();
// Get a normal and a point for the hyperplane:
AVector nv(fra1, ScalarList(1.0, 1.0, 1.0, 0.0));
Vector norm = nv.Dual();
APoint pt(fra1, ScalarList(0.5, 0.5, 0.5, 1.0));
// Define the map by describing the action of the hyperplane
// on the standard simplex:
GeObList res(workspace.Dim() + 1);
for (int i = 0; i <= workspace.Dim(); i++) {
res[i] = norm.Apply(smp1[i] - pt);
}
AffineMap hyp(smp1, Reals.FullSet(), res);
// Given a line segment that intersects the hyperplane, compute
// the point of intersection:
APoint endpt1(fra1, ScalarList(-2.3, -7.8, -11.2, 1.0));
APoint endpt2(fra1, ScalarList(4.6, 5.8, 6.7, 1.0));
Scalar d1 = fabs(hyp(endpt1).ToScalar());
Scalar d2 = fabs(hyp(endpt2).ToScalar());
APoint intsct = (d1 / (d1 + d2)) * endpt2 +
(d2 / (d1 + d2)) * endpt1;
// This point is in the hyperplane:
MLM cross = workspace.GetSpace(TANGENT).CrossProduct();
Scalar outp =
hyp(pt + cross(GeObList(nv, fra1[0]))).ToScalar();
cout << "Output: " << outp << "\n";
cout << intsct;
outp = hyp(intsct).ToScalar();
cout << "Output: " << outp << "\n";
}
// ***********************************************************************
void thex7(void)
{
// The map carries projective points from a 2-dimensional space
// to a 1-dimensional subset of another 2-dimensional space:
PSpace domsp("Domain space", 2);
HFrame fra1 = domsp.StdBasis();
PSpace rngsp("Range space", 2);
HFrame fra2 = rngsp.StdBasis();
// Construct the domain subset, which can be viewed as modeling
// a pencil of lines through the point p1. Points p1, p4, and
// p2 define a plane in the embedding space. The point p1 is
// then removed from this plane, creating the subset:
PPoint p1(fra1, ScalarList(6.7, 2.3, 7.5));
PPoint p2(fra1, ScalarList(3.6, -1.4, 2.2));
PPoint p3(fra1, ScalarList(1.1, 0.2, 1.0));
PPoint p4(fra1, ScalarList(5.6, 3.4, -9.1));
PSubSet domsub("Domain subset", domsp,
GeObList(p1), GeObList(p4, p2));
// Create the range subset, which consists of all the points on
// the line pr1pr2:
PPoint pr1(fra2, ScalarList(10.7, 3.4, 1.1));
PPoint pr2(fra2, ScalarList(5.6, -1.4, 12.2));
PPoint pr3(fra2, ScalarList(16.3, 2.0, 13.3));
PSubSet rngsub("Range subset", rngsp, GeObList(pr1, pr2));
// Create the non-invertible map:
ProjectiveMap pm1(domsub, GeObList(p4, p2, p3),
rngsub, GeObList(pr1, pr2, pr3));
// Send a point through the projective map. The algebraic
// operations on projective points are performed in the
// context of the standard affine subset defined on the
// projective space:
PPoint ppo = pm1((p1 + p2) / 2.0);
// Obtain the homogeneous coordinates of the resulting point:
ScalarList ppoCoords = fra2(ppo);
cout << ppoCoords;
ppo = pm1(p4);
ppoCoords = fra2(ppo);
cout << ppoCoords;
ppo = pm1(p2);
ppoCoords = fra2(ppo);
cout << ppoCoords;
ppo = pm1(p3);
ppoCoords = fra2(ppo);
cout << ppoCoords;
ppo = pm1((p1 + p4) / 2.0);
ppoCoords = fra2(ppo);
cout << ppoCoords;
}